// types.cpp : Defines basic types (vectors, ray, color), and operations on it.
//

#include <cmath>
#include <iostream>
#include <string>
#include <sstream>

#include "types.hpp"

using namespace std;

Vector3::Vector3(double x, double y, double z)
{
	x_ = x;
	y_ = y;
	z_ = z;
}

ostream& operator<<(ostream& os, const Vector3& dt)
{
	os << "(" << dt.x_ << ", " << dt.y_ << ", " << dt.z_ << ")";
	return os;
}

double Vector3::getX() const
{
	return x_;
}

double Vector3::getY() const
{
	return y_;
}

double Vector3::getZ() const
{
	return z_;
}

void Vector3::setX(double x)
{
	x_ = x;
}

void Vector3::setY(double y)
{
	y_ = y;
}

void Vector3::setZ(double z)
{
	z_ = z;
}

Vector3 Vector3::operator+(const Vector3& arg) const
{
	return Vector3(x_ + arg.x_, y_ + arg.y_, z_ + arg.z_);
}

Vector3 Vector3::operator-(const Vector3& arg) const
{
	return Vector3(x_ - arg.x_, y_ - arg.y_, z_ - arg.z_);
}

Vector3 Vector3::operator*(const Vector3& arg) const
{
	return Vector3(y_ * arg.z_ - z_ * arg.y_, z_ * arg.x_ - x_ * arg.z_, x_ * arg.y_ - y_ * arg.x_);
}

Vector3 Vector3::operator*(double arg) const
{
	return Vector3(x_ * arg, y_ * arg, z_ * arg);
}

double dot(const Vector3& v1, const Vector3& v2)
{
	return v1.x_ * v2.x_ + v1.y_ * v2.y_ + v1.z_ * v2.z_;
}

double mod(const Vector3& v)
{
	return sqrt(v.x_ * v.x_ + v.y_ * v.y_ + v.z_ * v.z_);
}

Vector3 normalize(const Vector3& v)
{
	return v * (1.0 / mod(v));
}

Ray::Ray(Vector3 origin, Vector3 direction)
{
	origin_ = origin;
	direction_ = normalize(direction);
}

ostream& operator<<(ostream& os, const Ray& dt)
{
	os << "ray" << dt.origin_ << "->" << dt.direction_;
	return os;
}

Vector3 Ray::getOrigin() const
{
	return origin_;
}

Vector3 Ray::getDirection() const
{
	return direction_;
}

Color::Color(double r, double g, double b)
{
	r_ = r;
	g_ = g;
	b_ = b;
}

Color Color::operator*(const Color& c) const
{
	return Color(r_ * c.r_, g_ * c.g_, b_ * c.b_);
}

Color Color::operator*(double k) const
{
	return Color(r_ * k, g_ * k, b_ * k);
}

Color Color::operator+(const Color& c) const
{
	return Color(r_ + c.r_, g_ + c.g_, b_ + c.b_);
}

double Color::getR() const
{
	return r_;
}

double Color::getG() const
{
	return g_;
}

double Color::getB() const
{
	return b_;
}

ostream& operator<<(ostream& os, const Color& dt)
{
	os << "c" << "R" << dt.getR() << "G" << dt.getG() << "B" << dt.getB();
	return os;
}
